1 Intro

1.1 Aim

  • Aquire tRNA gene methylation data for fetal tissues, in order to establish if tRNAs are hypomethylated in fetal tissues

(Yang et al. 2016) created “epiTOC” (Epigenetic Timer Of Cancer) and used DNAm data from fetal tissues:

Age-hypermethylated CpGs were filtered further, selecting only those with absent or low (beta <0.2) methylation across 52 fetal tissue samples encompassing 11 tissue types (cord blood (GSE72867), stomach, heart, tongue, kidney, liver, brain, thymus, spleen, lung, adrenal gland (Nazor et al. 2012)).

The methylation data takes the form of mixed 450k and 27k illumina bead-chip methylation array beta values.

(Nazor et al. 2012) Tissue specific methylation data is under: GSE30654, which contains samples other than the fetal samples so accessions for the tissues listed in (Yang et al. 2016) were selected, this totaled 51 samples from 10 tissue types.

The epiTOC paper referenced GSE72867 for cord blood this contained 450k array data for CD34+ cells from cord blood including 5 controls each with 3 technical replicates. As there was no additional information on which samples were used from this set all the control samples were used, taking the mean of the technical replicates.

Specific accessions for the selected samples were compiled into a list (see below)

2 Setup

2.1 libs

suppressPackageStartupMessages({
    library(tidyverse)
    library(broom)
    library(rvest)
    library(plotly)
    
    library(heatmaply)
    library(ComplexHeatmap)
})
nest <- nest_legacy
unnest <- unnest_legacy
if(!dir.exists("graphics")){
    dir.create("graphics", showWarnings = FALSE, recursive = TRUE)
}

2.2 data read-in

2.2.1 accession from samples used in epiTOC

epiTOCfetalTissues <- read_csv("data/epiTOC_fetal_DNAm_datasets.csv")
Parsed with column specification:
cols(
  stomach = col_character(),
  heart = col_character(),
  tongue = col_character(),
  kidney = col_character(),
  liver = col_character(),
  brain = col_character(),
  thymus = col_character(),
  spleen = col_character(),
  lung = col_character(),
  `adrenal gland` = col_character(),
  cord_blood = col_character(),
  cordBlood_groups = col_character()
)
epiTOCfetalTissuesL <- epiTOCfetalTissues %>% 
    gather(key = "tissue", value = "accession", stomach:cord_blood) %>%
    na.omit() %>%
    mutate(
        cordBlood_groups = if_else(
            grepl(x = tissue, pattern = "cord_blood"), cordBlood_groups, "NA"
        )
    )

2.2.2 tRNA data

tRNAprobes <- read_delim(
    delim = "\t",
    file = "../tRNA-GtRNAdb/450k_coresponding_hg19tRNAs.bed",
    col_names = c(
        "pChr","pStart","pEnd","probeID",
        as.character(
            read_delim(
                delim = "\t",
                file = "../tRNA-GtRNAdb/std_tRNA_header.txt",
                col_names = FALSE
            )
        )
    )
)
Parsed with column specification:
cols(
  X1 = col_character(),
  X2 = col_character(),
  X3 = col_character(),
  X4 = col_character(),
  X5 = col_character(),
  X6 = col_character(),
  X7 = col_character(),
  X8 = col_character(),
  X9 = col_character(),
  X10 = col_character(),
  X11 = col_character(),
  X12 = col_character()
)
Parsed with column specification:
cols(
  pChr = col_character(),
  pStart = col_double(),
  pEnd = col_double(),
  probeID = col_character(),
  tChr = col_character(),
  tStart = col_double(),
  tEnd = col_double(),
  tRNAname = col_character(),
  score = col_double(),
  strand = col_character(),
  thickStart = col_double(),
  thickEnd = col_double(),
  RGB = col_double(),
  blockCount = col_double(),
  blockSizes = col_number(),
  blockStarts = col_character()
)
tRNAge <- read_delim(
    delim = "\t",
    file = "../tRNA-GtRNAdb/GenWideSigWintRNAs.txt",
    col_names = "tRNAname",
    col_types = "c"
)
gwsBB6 <- read_tsv(
    "../tRNA-GtRNAdb/BB_GWS_tRNA.txt",
    col_names = "tRNAname", col_types = "c"
)

swsBB23 <- read_tsv(
    "../tRNA-GtRNAdb/swsBB23.tsv",
    col_names = "tRNAname", col_types = "c"
)

bltRNAs <- read_tsv(
    "../tRNA-GtRNAdb/tRNAs-in-hg19-blacklist-v2.txt",
    col_names = "tRNAname", col_types = "c"
)

2.2.4 Methylation data

2.2.4.1 Web-scrape

methylationArrayData <- lapply(
(epiTOCfetalTissuesL %>% 
    pull(accession)),
    function(x){
        paste0( "https://www.ncbi.nlm.nih.gov/geo/tools/geometa.cgi?acc=",
                x,
                "&scope=full&mode=miniml"
        ) %>%
        read_html() %>% #html_structure()
        html_nodes("internal-data") %>% #pre,x = "pre"
        html_text() %>%
        read_delim(delim = "\t", col_names = FALSE) %>% #c("probeID","beta","detection-p")
        mutate(accession=x)
    }
)
methylationArrayDataS <- lapply(methylationArrayData, function(x) {x %>% select(X1,X2,accession)})
methylationArrayDataDF <- do.call(rbind, methylationArrayDataS)
methylationArrayDataDF <- methylationArrayDataDF %>% rename(probeID = X1, beta = X2)
saveRDS(
    methylationArrayDataDF,
    file = "data/epiTOCFetal_methylationArrayDataDF.Rds"
)

2.2.4.2 Load Local data copy

methylationArrayDataDF <- readRDS(
    file = "data/epiTOCFetal_methylationArrayDataDF.Rds"
)

3 Data Overview

3.1 N probes per sample

methylationArrayDataDF %>%
    group_by(accession) %>%
    summarise(n = n())

3.2 Beta density plots

ggplotly(
    methylationArrayDataDF %>%
        ggplot(aes(beta, colour = accession)) + 
            geom_density() + 
            guides(colour=FALSE)
)

4 Data Processing

4.1 Mean betas from technical replicates

NB keeps an aribtary accession number from each sample for cross referencing with tissue type data

meanBloodBetas <- epiTOCfetalTissuesL %>% 
    filter(!cordBlood_groups == "NA") %>% 
    extract(
        col = cordBlood_groups,
        into = c("sample", "replicate"),
        regex = "(Ctrl\\d+)_(\\w)",
        remove = FALSE
    ) %>%
    group_by(sample) %>%
    do(meanBetas = {
        data <- .
        methylationArrayDataDF %>% 
        filter(
            accession %in% (data %>% pull(accession) )
        ) %>% 
        group_by(probeID) %>% 
        summarise(beta = mean(beta), accession = data$accession[1])
    })
saveRDS(
    meanBloodBetas,
    "data/epiTOCFetal_meanBloodBetas.Rds"
)
meanBloodBetas <- readRDS(
    "data/epiTOCFetal_meanBloodBetas.Rds"
)

Unnest and replace data with technical replicates with the mean values

methylationArrayDataReptMeansDF <-
bind_rows(
    methylationArrayDataDF %>%
        filter(
            accession %in% (
                epiTOCfetalTissuesL %>% 
                filter(cordBlood_groups == "NA") %>%
                pull(accession) 
            )
        ),
    meanBloodBetas %>% 
        unnest() %>%
        select(probeID, beta, accession)
)
saveRDS(
    methylationArrayDataReptMeansDF,
    file = "data/epiTOCFetal_methylationArrayDataReptMeansDF.Rds"
)

4.1.0.1 Load Local data copy

methylationArrayDataReptMeansDF <- readRDS(
    file = "data/epiTOCFetal_methylationArrayDataReptMeansDF.Rds"
) 

4.2 Get tissue categories

methylationArrayDataReptMeansDF <- left_join(
    methylationArrayDataReptMeansDF,
    epiTOCfetalTissuesL %>% select(tissue, accession),
    by = c("accession", "tissue")
)

5 Get meth data from tRNA probes

tRNAprobesMethData <- 
left_join(
    tRNAprobes,
    methylationArrayDataReptMeansDF,
    by = "probeID"
) %>% 
    extract(tRNAname,
            c("nmt","aa","codon"),
            "(\\w*)-?tRNA-(i?\\w{3})(?:\\w+)?-(\\w+)-",
            remove = FALSE
    ) %>% 
    mutate(tRNAge = tRNAname %in% (tRNAge %>% pull(tRNAname)))
tRNAmeanMethByTissue <-
tRNAprobesMethData %>%
    dplyr::select(probeID, tChr, pStart, tStart, tRNAname, nmt, aa, strand, codon, beta, accession, tissue, tRNAge) %>%
    dplyr::group_by(tChr, tStart, tRNAname, nmt, aa, strand, codon, tissue, accession, tRNAge) %>%
    summarise(beta = mean(beta))
tRNAmeanMethByTissue %>% nrow()
[1] 5344
tRNAmeanMethByTissue <- 
tRNAmeanMethByTissue %>%
    filter(!tRNAname %in% bltRNAs)

tRNAmeanMethByTissue %>% nrow()
[1] 5344

5.1 Number of tRNAs covered:

NtRNAgenes <- tRNAmeanMethByTissue %>%
    ungroup() %>%
    select(tRNAname) %>%
    distinct() %>%
    nrow()
NtRNAgenes
[1] 150

5.2 Number of tRNAge genes covered

NtRNAgeGenes <- tRNAmeanMethByTissue %>%
    ungroup() %>%
    filter(tRNAge == TRUE) %>%
    select(tRNAname) %>%
    distinct() %>%
    nrow()
NtRNAgeGenes
[1] 17
meanMethBytRNAByTissue <- tRNAprobesMethData %>%
    select(probeID,tChr,pStart,tStart,tRNAname,nmt,aa,strand,codon,beta,accession,tissue) %>%
    group_by(tChr,tStart,tRNAname,nmt,aa,strand,codon,tissue) %>%
    summarise(beta = mean(beta)) %>%
    ungroup()

# tRNAs with mean beta < 0.2 in 1 or more tissues
meanMethBytRNAByTissue %>%
    filter(beta < 0.2) %>% 
    select(tRNAname) %>% 
    distinct() %>%
    nrow()
[1] 130
# tRNAs with mean beta >= 0.2 in 1 or more tissues
meanMethBytRNAByTissue %>%
    filter(beta >= 0.2) %>% 
    select(tRNAname) %>% 
    distinct() %>%
    nrow()
[1] 48

5.3 tRNA mean metylation by tissue plots

5.3.1 Heatmaps

meanMethBytRNAByTissueMat <- 
tRNAmeanMethByTissue %>%
    ungroup() %>%
    select(tRNAname,tissue,beta) %>%
    group_by(tRNAname,tissue) %>%
    summarise(mean = mean(beta)) %>%
    drop_na(tissue) %>%
    spread(tissue,mean) %>%
    na.omit() %>%
    column_to_rownames("tRNAname") %>%
    data.matrix()

meanMethBytRNAByTissueMat %>% nrow()
[1] 115
col_fun <- circlize::colorRamp2(
    c(0, 0.5, 1),
    c("#ffff00", "#19ff00", "#0033cc")
)
meanMethBytRNAByTissueHeatmap <-
meanMethBytRNAByTissueMat %>%
    Heatmap(
        heatmap_width = unit(5.4,"inches"),
        heatmap_height = unit(11.8,"inches"),
        column_title_gp = gpar(fontsize = 11, fontface = "bold"),
        #"Fetal Tissue tRNA methylation",
        column_title = "Mean Methyation by tRNA\nin Fetal Tissue", 
        name = "Meth",
        column_names_rot = 45,
        row_dend_width = unit(0.2, "npc"),
        row_names_gp = gpar(fontsize = 6),
        row_title = "tRNA gene",
        col = col_fun
    )

png(
    filename = "graphics/meanMethBytRNAByFetalTissueHeatmap.png",
    #width = 9, height = 12, units = "in", res = 192
    width = 6, height = 12, units = "in", res = 192
)
meanMethBytRNAByTissueHeatmap
dev.off()
null device 
          1 
meanMethBytRNAByTissueHeatmap

meanMethBytRNAByTissueHeatmapAAsplit <-
meanMethBytRNAByTissueMat %>%
  Heatmap(
    heatmap_width = unit(5.4, "inches"),
    heatmap_height = unit(11.8, "inches"),
    column_title_gp = gpar(fontsize = 16, fontface = "bold"),
    column_title = "Mean Methyation by tRNA\nin Fetal Tissue",
    name = "Meth",
    column_names_rot = 45,
    row_dend_width = unit(0.2, "npc"),
    row_names_gp = gpar(fontsize = 6),
    row_split = rownames(meanMethBytRNAByTissueMat) %>%
      gsub(pattern = "tRNA-(\\w+)-\\w+-\\w+-\\d+", replacement = "\\1"),
    row_title = "tRNA gene",
    col = col_fun
  )

png(
  filename = "graphics/meanMethBytRNAByFetalTissueHeatmapAAsplit.png",
  #width = 9, height = 12, units = "in", res = 192
  width = 6, height = 12, units = "in", res = 192
  )
meanMethBytRNAByTissueHeatmapAAsplit
dev.off()
null device 
          1 
meanMethBytRNAByTissueHeatmapAAsplit

pseudoSplit <- tRNA$pseudo
names(pseudoSplit) <- tRNA$tRNAname
# pseudoSplit[rownames(meanMethBytRNAByTissueMat)]

meanMethBytRNAByTissueHeatmapPseudosplit <-
meanMethBytRNAByTissueMat %>%
    Heatmap(
        heatmap_width = unit(5.4, "inches"),
        heatmap_height = unit(11.8, "inches"),
        column_title_gp = gpar(fontsize = 16, fontface = "bold"),
        column_title = "Mean Methyation by tRNA\nin Fetal Tissue",
        name = "Meth",
        column_names_rot = 45,
        row_dend_width = unit(0.2, "npc"),
        row_names_gp = gpar(fontsize = 6),
        row_split = pseudoSplit[rownames(meanMethBytRNAByTissueMat)],
        row_title = "tRNA gene",
        col = col_fun
    )

png(
    filename = "graphics/meanMethBytRNAByFetalTissueHeatmapPseudosplit.png",
    #width = 9, height = 12, units = "in", res = 192
    width = 6, height = 12, units = "in", res = 192
)
meanMethBytRNAByTissueHeatmapPseudosplit
dev.off()
null device 
          1 
meanMethBytRNAByTissueHeatmapPseudosplit

heatmaply(meanMethBytRNAByTissueMat)

5.3.2 Boxplots

# custom labeler: (character vector in and out)
tRNA_labeller <- function(value) {sapply(value,
    function(n){
    tRNAmeanMethByTissue %>%
        ungroup() %>%
        select(tRNAname,tChr,strand) %>%
        distinct() %>%
        filter(tRNAname==as.character(n)) %>%
        unlist() %>%
        (function(d) paste0(d["tRNAname"]," (",d["strand"],") ",d["tChr"])) %>%
        return()
    }
)}
plots <- tRNAmeanMethByTissue %>%
    group_by(aa) %>%
        do(plot = 
            ggplot(.,aes(tissue,beta)) +
                #geom_point() +
                geom_boxplot(aes(fill=tissue)) + 
                guides(fill=FALSE) +
                ylim(0,1) +
                facet_wrap(~tRNAname,labeller = labeller(tRNAname = tRNA_labeller)) + #,scales = "free_y"
                geom_hline(aes(colour=tRNAge,yintercept = 0.2)) +
                scale_colour_manual(values = c("TRUE"="red","FALSE"="black"),drop=FALSE) +
                labs(   title = paste0("tRNA genes which are ",.$aa," isoacceptors"),
                        subtitle = "mean methylation across all probes in a tRNA gene for each fetal tissue"
                ) + 
                theme(axis.text.x = element_text(angle = 90,vjust = 0.5))
        )

plots$plot
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

[[7]]

[[8]]

[[9]]

[[10]]

[[11]]

[[12]]

[[13]]

[[14]]

[[15]]

[[16]]

[[17]]

[[18]]

[[19]]

[[20]]

#plots$plot[[3]]
#plots %>% filter(aa=="iMet") %>% pull(plot)
nil <- plots %>% do(out=ggsave(plot = .$plot,
                    filename = paste0("graphics/epiTOCfetalTissuestRNAMethylation/tRNAmeanMethByTissue_" , .$aa , ".png"),
                    width = 12,
                    height = 6.75
                ))
rm(nil)

6 Differential methylation by tissue

6.1 Kruskal-Wallis test

nestedBytRNA <- tRNAprobesMethData %>% 
    nest(-tRNAname)

KWtissueBeta <- nestedBytRNA %>% 
    group_by(tRNAname) %>%
    mutate(test=purrr::map(data, ~kruskal.test(tissue ~ beta, data = .)))#aov

KWtissueBetaGlance <- KWtissueBeta %>% unnest(test %>% purrr::map(broom::glance))
KWtissueBetaGlance %>%
    ggplot(aes(tRNAname,p.value)) + 
        geom_col() + 
        geom_hline(yintercept = 0.05,colour="red") +
        theme(axis.text.x = element_text(angle=90,vjust = 0.5))

No tRNAs for which methylation was significantly different between tissues by Kruskal-Wallis rank sum test

7 Codons

7.1 Mean meth by codon

tRNAmeanMethByTissue %>%
    ggplot(.,aes(tissue,beta)) +#,group=aa
        stat_summary(fun.data = "mean_cl_boot")+
        guides(fill=FALSE) +
        ylim(0,1) +
        facet_wrap(~codon) + #,scales = "free_y"#labeller = labeller(tRNAname = tRNA_labeller)
        geom_hline(aes(colour=tRNAge,yintercept = 0.2)) +
        scale_colour_manual(values = c("TRUE"="red","FALSE"="black"),drop=FALSE) +
        # labs( title = "x",#paste0("tRNA genes which are ",.$aa," isoacceptors"),
        #       subtitle = "mean methylation across all probes in a tRNA gene for each fetal tissue"
        # ) + 
        theme(axis.text.x = element_text(angle = 90,vjust = 0.5))

tRNAs with certain codons seem more methylated than others, some of the more methylated codons seemed to correspond to those that divered from expectation based on frequency of occurance in the exom see below. e.g. GTT, CTT. Therefore I took a look the relationship between mean methylation levels on tRNAs with a given codon and residuals for the relationship between number of tRNA genes and codon fequency.

revTrans <- function(x){
        ntPairs <- data.frame("sense" = c("A","T","G","C","N"),
                              "antisense"=c("T","A","C","G","N"),
                              stringsAsFactors = FALSE)
        strsplit(x, NULL) %>%
        lapply(rev) %>%
        lapply(function(x) ntPairs$antisense[match(x,ntPairs$sense)]) %>%
        sapply(paste, collapse="")
    }

aaBycodon <- tRNA %>% select(aa,codon) %>% unique()
aaBycodon$codon <- aaBycodon$codon %>% revTrans()

AAUsageFreqHuman <- inner_join(
CodonUsageFreqHuman,
aaBycodon,
by="codon") 

NtRNAbyaa <- tRNA %>% 
    group_by(aa) %>% 
    ###
    summarise("NtRNA"=n())
NtRNAbyCodon <- 
tRNA %>% 
    group_by(codon) %>% 
    summarise("NtRNA"=n())


codonUsageFreqNtRNA <- 
inner_join(
    AAUsageFreqHuman %>% group_by(codon),
    NtRNAbyCodon %>% select(codon,NtRNA),
    by="codon"
)

codonUsageFreqNtRNAplot <- 
ggplot(codonUsageFreqNtRNA,aes(countPerThousand,NtRNA)) +
    geom_label(aes(label=codon,fill=aa),size=4,colour="white",alpha=0.8) +
    scale_fill_manual(values = palette) +
    geom_smooth(method = "lm",se=FALSE) +
    labs(   x = "Codon Usage / count per thousand",
            y = "Number of tRNA genes"
    ) + 
    guides(fill=guide_legend(title="Amino Acid")) + 
    geom_text(x=35,y=17,
            label=paste0(   'italic(r)~',
                            '"="~',
                            sprintf("%0.2f",
                                round((cor(codonUsageFreqNtRNA$countPerThousand,codonUsageFreqNtRNA$NtRNA)),
                                digits = 2))
                            ),
            parse = TRUE
    )

codonUsageFreqNtRNAplot


#ggsave(codonUsageFreqNtRNAplot,filename = "graphics/codonUsageFreqNtRNAplot.png",width=8,height=4.5)
codonUsageVsNtRNA <- lm(codonUsageFreqNtRNA$countPerThousand~codonUsageFreqNtRNA$NtRNA)
codonUsageVsNtRNA %>% summary()

Call:
lm(formula = codonUsageFreqNtRNA$countPerThousand ~ codonUsageFreqNtRNA$NtRNA)

Residuals:
    Min      1Q  Median      3Q     Max 
-14.362  -4.088  -1.052   3.631  20.084 

Coefficients:
                          Estimate Std. Error t value
(Intercept)                12.9939     1.7180   7.563
codonUsageFreqNtRNA$NtRNA   0.2020     0.1284   1.573
                          Pr(>|t|)    
(Intercept)               7.92e-10 ***
codonUsageFreqNtRNA$NtRNA    0.122    
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.045 on 50 degrees of freedom
Multiple R-squared:  0.04714,   Adjusted R-squared:  0.02808 
F-statistic: 2.474 on 1 and 50 DF,  p-value: 0.1221
model <- left_join(
    augment(codonUsageVsNtRNA) %>%
        rename(
            "countPerThousand" = "codonUsageFreqNtRNA.countPerThousand",
            "NtRNA" = "codonUsageFreqNtRNA.NtRNA"
        ),
    codonUsageFreqNtRNA,
    by=c("countPerThousand","NtRNA")
)
meanMethBycodon <- tRNAprobesMethData %>% 
    group_by(codon) %>% 
    summarise(beta=mean(beta)) %>% 
    mutate(codon=revTrans(codon))
modelMeanMeth <- left_join(model,meanMethBycodon,by="codon")
modelMeanMeth

FetalMeanMethVsCodonUsageNtRNAGap <- 
modelMeanMeth %>%
    ggplot(aes(.resid,beta)) + 
        geom_label(aes(label=codon,fill=aa),size=4,colour="white",alpha=0.8) +
        scale_fill_manual(values = palette) +
        geom_smooth(method="lm") +
        labs(   title="Fetal tissue tRNA methylation",
                subtitle = "Relationship of methylation level to 'gap' between tRNA gene number and usage frequency",
                x = "Residuals from: Codon Usage Count ~ Number of tRNA genes",
                y = "Mean methylation across probes in tRNA genes /proportion methylated"
        )+
        guides(fill=guide_legend(title="Amino Acid")) + 
        geom_text(x=10,y=0.6,
                label=paste0(   'italic(R^2)~',
                                '"="~',
                                sprintf("%0.2f",
                                    round(glance(codonUsageVsNtRNA)$r.squared,
                                    digits = 4))
                                ),
                parse = TRUE
        )

# FetalMeanMethVsCodonUsageNtRNAGap %>% 
#   ggsave(filename = "../graphics/FetalMeanMethVsCodonUsageNtRNAGap.png",
#       width = 12,
#       height = 6.75
#   )

FetalMeanMethVsCodonUsageNtRNAGap

8 Session Info

sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 19.10

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.3.7.so

locale:
 [1] LC_CTYPE=en_GB.UTF-8      
 [2] LC_NUMERIC=C              
 [3] LC_TIME=en_GB.UTF-8       
 [4] LC_COLLATE=en_GB.UTF-8    
 [5] LC_MONETARY=en_GB.UTF-8   
 [6] LC_MESSAGES=en_GB.UTF-8   
 [7] LC_PAPER=en_GB.UTF-8      
 [8] LC_NAME=C                 
 [9] LC_ADDRESS=C              
[10] LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8
[12] LC_IDENTIFICATION=C       

attached base packages:
[1] grid      stats     graphics  grDevices utils    
[6] datasets  methods   base     

other attached packages:
 [1] ComplexHeatmap_2.1.0 heatmaply_0.16.0    
 [3] viridis_0.5.1        viridisLite_0.3.0   
 [5] plotly_4.9.0         rvest_0.3.4         
 [7] xml2_1.2.2           broom_0.5.2         
 [9] forcats_0.4.0        stringr_1.4.0       
[11] dplyr_0.8.3          purrr_0.3.2         
[13] readr_1.3.1          tidyr_1.0.0         
[15] tibble_2.1.3         ggplot2_3.2.1       
[17] tidyverse_1.2.1      testthat_2.2.1      
[19] devtools_2.2.0       usethis_1.5.1       
[21] reprex_0.3.0        

loaded via a namespace (and not attached):
  [1] colorspace_1.4-1    rjson_0.2.20       
  [3] ellipsis_0.2.0.1    rprojroot_1.3-2    
  [5] htmlTable_1.13.1    circlize_0.4.8     
  [7] base64enc_0.1-3     GlobalOptions_0.1.0
  [9] fs_1.3.1            clue_0.3-57        
 [11] rstudioapi_0.10     remotes_2.1.0      
 [13] DT_0.9              lubridate_1.7.4    
 [15] splines_3.6.1       codetools_0.2-16   
 [17] knitr_1.24          pkgload_1.0.2      
 [19] zeallot_0.1.0       Formula_1.2-3      
 [21] jsonlite_1.6        Cairo_1.5-10       
 [23] packrat_0.5.0       cluster_2.1.0      
 [25] png_0.1-7           shiny_1.3.2        
 [27] compiler_3.6.1      httr_1.4.1         
 [29] backports_1.1.4     Matrix_1.2-17      
 [31] assertthat_0.2.1    lazyeval_0.2.2     
 [33] cli_1.1.0           later_0.8.0        
 [35] acepack_1.4.1       htmltools_0.3.6    
 [37] prettyunits_1.0.2   tools_3.6.1        
 [39] gtable_0.3.0        glue_1.3.1         
 [41] reshape2_1.4.3      Rcpp_1.0.2         
 [43] cellranger_1.1.0    vctrs_0.2.0        
 [45] gdata_2.18.0        nlme_3.1-141       
 [47] iterators_1.0.12    crosstalk_1.0.0    
 [49] xfun_0.9            ps_1.3.0           
 [51] mime_0.7            lifecycle_0.1.0    
 [53] gtools_3.8.1        dendextend_1.12.0  
 [55] MASS_7.3-51.4       scales_1.0.0       
 [57] TSP_1.1-7           hms_0.5.1          
 [59] promises_1.0.1      parallel_3.6.1     
 [61] RColorBrewer_1.1-2  yaml_2.2.0         
 [63] memoise_1.1.0       gridExtra_2.3      
 [65] rpart_4.1-15        latticeExtra_0.6-28
 [67] stringi_1.4.3       gclus_1.3.2        
 [69] desc_1.2.0          foreach_1.4.7      
 [71] checkmate_1.9.4     seriation_1.2-8    
 [73] caTools_1.17.1.2    pkgbuild_1.0.5     
 [75] shape_1.4.4         rlang_0.4.0        
 [77] pkgconfig_2.0.2     bitops_1.0-6       
 [79] lattice_0.20-38     htmlwidgets_1.3    
 [81] labeling_0.3        processx_3.4.1     
 [83] tidyselect_0.2.5    plyr_1.8.4         
 [85] magrittr_1.5        R6_2.4.0           
 [87] Hmisc_4.2-0         gplots_3.0.1.1     
 [89] generics_0.0.2      foreign_0.8-72     
 [91] pillar_1.4.2        haven_2.1.1        
 [93] withr_2.1.2         nnet_7.3-12        
 [95] survival_2.44-1.1   modelr_0.1.5       
 [97] crayon_1.3.4        KernSmooth_2.23-16 
 [99] GetoptLong_0.1.7    readxl_1.3.1       
[101] data.table_1.12.2   callr_3.3.1        
[103] digest_0.6.20       webshot_0.5.1      
[105] xtable_1.8-4        httpuv_1.5.2.9000  
[107] munsell_0.5.0       registry_0.5-1     
[109] sessioninfo_1.1.1  

9 References

Nazor, Kristopher L., Gulsah Altun, Candace Lynch, Ha Tran, Julie V. Harness, Ileana Slavin, Ibon Garitaonandia, et al. 2012. “Recurrent Variations in DNA Methylation in Human Pluripotent Stem Cells and Their Differentiated Derivatives.” Cell Stem Cell 10 (5): 620–34. https://doi.org/10.1016/j.stem.2012.02.013.

Yang, Zhen, Andrew Wong, Diana Kuh, Dirk S. Paul, Vardhman K. Rakyan, R. David Leslie, Shijie C. Zheng, Martin Widschwendter, Stephan Beck, and Andrew E. Teschendorff. 2016. “Correlation of an epigenetic mitotic clock with cancer risk.” Genome Biology 17 (1): 205. https://doi.org/10.1186/s13059-016-1064-3.

LS0tCnRpdGxlOiAidFJOQSBtZXRoeWxhdGlvbiBpbiBmZXRhbCB0aXNzdWVzIgphdXRob3I6ICJSaWNoYXJkIEouIEFjdG9uIgpkYXRlOiAiMjAxOC0xMC0xNyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBkZl9wcmludDogcGFnZWQKICBodG1sX25vdGVib29rOgogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwpiaWJsaW9ncmFwaHk6ICJgciBub3JtYWxpemVQYXRoKCcuLi9saWJyYXJ5LmJpYicpYCIKLS0tCgojIEludHJvCgojIyBBaW0KCi0gQXF1aXJlIHRSTkEgZ2VuZSBtZXRoeWxhdGlvbiBkYXRhIGZvciBmZXRhbCB0aXNzdWVzLCBpbiBvcmRlciB0byBlc3RhYmxpc2ggaWYgdFJOQXMgYXJlIGh5cG9tZXRoeWxhdGVkIGluIGZldGFsIHRpc3N1ZXMKCgpbQFlhbmcyMDE2XSBjcmVhdGVkICJlcGlUT0MiIChFcGlnZW5ldGljIFRpbWVyIE9mIENhbmNlcikgYW5kIHVzZWQgRE5BbSBkYXRhIGZyb20gZmV0YWwgdGlzc3VlczoKCj4gQWdlLWh5cGVybWV0aHlsYXRlZCBDcEdzIHdlcmUgZmlsdGVyZWQgZnVydGhlciwgc2VsZWN0aW5nIG9ubHkgdGhvc2Ugd2l0aCBhYnNlbnQgb3IgbG93IChiZXRhIDwwLjIpIG1ldGh5bGF0aW9uIGFjcm9zcyA1MiBmZXRhbCB0aXNzdWUgc2FtcGxlcyBlbmNvbXBhc3NpbmcgMTEgdGlzc3VlIHR5cGVzIChjb3JkIGJsb29kIChbR1NFNzI4NjddKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvZ2VvL3F1ZXJ5L2FjYy5jZ2k/YWNjPUdTRTcyODY3KSksIHN0b21hY2gsIGhlYXJ0LCB0b25ndWUsIGtpZG5leSwgbGl2ZXIsIGJyYWluLCB0aHltdXMsIHNwbGVlbiwgbHVuZywgYWRyZW5hbCBnbGFuZCBbQE5hem9yMjAxMl0pLgoKVGhlIG1ldGh5bGF0aW9uIGRhdGEgdGFrZXMgdGhlIGZvcm0gb2YgbWl4ZWQgNDUwayBhbmQgMjdrIGlsbHVtaW5hIGJlYWQtY2hpcCBtZXRoeWxhdGlvbiBhcnJheSBiZXRhIHZhbHVlcy4KCltATmF6b3IyMDEyXSBUaXNzdWUgc3BlY2lmaWMgbWV0aHlsYXRpb24gZGF0YSBpcyB1bmRlcjogW0dTRTMwNjU0XShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2dlby9xdWVyeS9hY2MuY2dpP2FjYz1HU0UzMDY1NCksIHdoaWNoIGNvbnRhaW5zIHNhbXBsZXMgb3RoZXIgdGhhbiB0aGUgZmV0YWwgc2FtcGxlcyBzbyBhY2Nlc3Npb25zIGZvciB0aGUgdGlzc3VlcyBsaXN0ZWQgaW4gW0BZYW5nMjAxNl0gd2VyZSBzZWxlY3RlZCwgdGhpcyB0b3RhbGVkIDUxIHNhbXBsZXMgZnJvbSAxMCB0aXNzdWUgdHlwZXMuCgpUaGUgZXBpVE9DIHBhcGVyIHJlZmVyZW5jZWQgR1NFNzI4NjcgZm9yIGNvcmQgYmxvb2QgdGhpcyBjb250YWluZWQgNDUwayBhcnJheSBkYXRhIGZvciBDRDM0KyBjZWxscyBmcm9tIGNvcmQgYmxvb2QgaW5jbHVkaW5nIDUgY29udHJvbHMgZWFjaCB3aXRoIDMgdGVjaG5pY2FsIHJlcGxpY2F0ZXMuIEFzIHRoZXJlIHdhcyBubyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIHdoaWNoIHNhbXBsZXMgd2VyZSB1c2VkIGZyb20gdGhpcyBzZXQgYWxsIHRoZSBjb250cm9sIHNhbXBsZXMgd2VyZSB1c2VkLCB0YWtpbmcgdGhlIG1lYW4gb2YgdGhlIHRlY2huaWNhbCByZXBsaWNhdGVzLgoKU3BlY2lmaWMgYWNjZXNzaW9ucyBmb3IgdGhlIHNlbGVjdGVkIHNhbXBsZXMgd2VyZSBjb21waWxlZCBpbnRvIGEgW2xpc3RdKH4vRG9jdW1lbnRzL1BoRF9TdHVmZi9waGQvUHJvamVjdHMvdFJOQV9TdHVmZi9kYXRhL2VwaVRPQ19mZXRhbF9ETkFtX2RhdGFzZXRzLmNzdikgKHNlZSBiZWxvdykKCiMgU2V0dXAKCiMjIGxpYnMKCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewoJbGlicmFyeSh0aWR5dmVyc2UpCglsaWJyYXJ5KGJyb29tKQoJbGlicmFyeShydmVzdCkKCWxpYnJhcnkocGxvdGx5KQoJCglsaWJyYXJ5KGhlYXRtYXBseSkKCWxpYnJhcnkoQ29tcGxleEhlYXRtYXApCn0pCmBgYAoKYGBge3J9Cm5lc3QgPC0gbmVzdF9sZWdhY3kKdW5uZXN0IDwtIHVubmVzdF9sZWdhY3kKYGBgCgpgYGB7cn0KaWYoIWRpci5leGlzdHMoImdyYXBoaWNzIikpewoJZGlyLmNyZWF0ZSgiZ3JhcGhpY3MiLCBzaG93V2FybmluZ3MgPSBGQUxTRSwgcmVjdXJzaXZlID0gVFJVRSkKfQpgYGAKCiMjIGRhdGEgcmVhZC1pbgoKIyMjIGFjY2Vzc2lvbiBmcm9tIHNhbXBsZXMgdXNlZCBpbiBlcGlUT0MKCmBgYHtyfQplcGlUT0NmZXRhbFRpc3N1ZXMgPC0gcmVhZF9jc3YoImRhdGEvZXBpVE9DX2ZldGFsX0ROQW1fZGF0YXNldHMuY3N2IikKYGBgCgpgYGB7cn0KZXBpVE9DZmV0YWxUaXNzdWVzTCA8LSBlcGlUT0NmZXRhbFRpc3N1ZXMgJT4lIAoJZ2F0aGVyKGtleSA9ICJ0aXNzdWUiLCB2YWx1ZSA9ICJhY2Nlc3Npb24iLCBzdG9tYWNoOmNvcmRfYmxvb2QpICU+JQoJbmEub21pdCgpICU+JQoJbXV0YXRlKAoJCWNvcmRCbG9vZF9ncm91cHMgPSBpZl9lbHNlKAoJCQlncmVwbCh4ID0gdGlzc3VlLCBwYXR0ZXJuID0gImNvcmRfYmxvb2QiKSwgY29yZEJsb29kX2dyb3VwcywgIk5BIgoJCSkKCSkKYGBgCgojIyMgdFJOQSBkYXRhCgpgYGB7cn0KdFJOQXByb2JlcyA8LSByZWFkX2RlbGltKAoJZGVsaW0gPSAiXHQiLAoJZmlsZSA9ICIuLi90Uk5BLUd0Uk5BZGIvNDUwa19jb3Jlc3BvbmRpbmdfaGcxOXRSTkFzLmJlZCIsCgljb2xfbmFtZXMgPSBjKAoJCSJwQ2hyIiwicFN0YXJ0IiwicEVuZCIsInByb2JlSUQiLAoJCWFzLmNoYXJhY3RlcigKCQkJcmVhZF9kZWxpbSgKCQkJCWRlbGltID0gIlx0IiwKCQkJCWZpbGUgPSAiLi4vdFJOQS1HdFJOQWRiL3N0ZF90Uk5BX2hlYWRlci50eHQiLAoJCQkJY29sX25hbWVzID0gRkFMU0UKCQkJKQoJCSkKCSkKKQpgYGAKCmBgYHtyfQp0Uk5BZ2UgPC0gcmVhZF9kZWxpbSgKCWRlbGltID0gIlx0IiwKCWZpbGUgPSAiLi4vdFJOQS1HdFJOQWRiL0dlbldpZGVTaWdXaW50Uk5Bcy50eHQiLAoJY29sX25hbWVzID0gInRSTkFuYW1lIiwKCWNvbF90eXBlcyA9ICJjIgopCmBgYAoKYGBge3J9Cmd3c0JCNiA8LSByZWFkX3RzdigKCSIuLi90Uk5BLUd0Uk5BZGIvQkJfR1dTX3RSTkEudHh0IiwKCWNvbF9uYW1lcyA9ICJ0Uk5BbmFtZSIsIGNvbF90eXBlcyA9ICJjIgopCgpzd3NCQjIzIDwtIHJlYWRfdHN2KAoJIi4uL3RSTkEtR3RSTkFkYi9zd3NCQjIzLnRzdiIsCgljb2xfbmFtZXMgPSAidFJOQW5hbWUiLCBjb2xfdHlwZXMgPSAiYyIKKQoKYmx0Uk5BcyA8LSByZWFkX3RzdigKCSIuLi90Uk5BLUd0Uk5BZGIvdFJOQXMtaW4taGcxOS1ibGFja2xpc3QtdjIudHh0IiwKCWNvbF9uYW1lcyA9ICJ0Uk5BbmFtZSIsIGNvbF90eXBlcyA9ICJjIgopCmBgYAoKIyMjIENvZG9uIFVzYWdlIGRhdGEgLyByZWxhdGVkIHRSTkEgZGF0YQoKYGBge3J9CnRSTkEgPC0gcmVhZC50YWJsZSgiLi4vdFJOQS1HdFJOQWRiL2hnMTktdFJOQXMtU2VxU3RyUHNldS5iZWQiKSAKCmNvbG5hbWVzKHRSTkEpIDwtIApjKAoJYXMuY2hhcmFjdGVyKAoJCXJlYWQudGFibGUoCgkJCSIuLi90Uk5BLUd0Uk5BZGIvc3RkX3RSTkFfaGVhZGVyLnR4dCIsCgkJCXN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQoJCSkKCSksCgkicHNldWRvIiwic3RyIiwic2VxIgopCgp0Uk5BIDwtIHRSTkEgJT4lCglleHRyYWN0KAoJCXRSTkFuYW1lLAoJCWMoIm5tdCIsICJhYSIsICJjb2RvbiIpLAoJCSIoXFx3KiktP3RSTkEtKGk/XFx3ezN9KSg/OlxcdyspPy0oXFx3KyktIiwKCQlyZW1vdmUgPSBGQUxTRQoJKQoKYGBgCgpgYGB7cn0KcGFsZXR0ZSA8LSBjKCIjZTYxOTRiIiwiIzNjYjQ0YiIsIiM0MjQyNDIiLCIjMDA4MmM4IiwiI2Y1ODIzMSIsIiM5MTFlYjQiLCIjNDZmMGYwIiwiI2YwMzJlNiIsIiNkMmY1M2MiLCIjZmFiZWJlIiwKICAgICAgICAgICAgICIjMDA4MDgwIiwiI2U2YmVmZiIsIiNhYTZlMjgiLCIjZmZmYWM4IiwiIzgwMDAwMCIsIiNhYWZmYzMiLCIjODA4MDAwIiwiI2ZmZDhiMSIsIiMwMDAwODAiLCIjODA4MDgwIiwKICAgICAgICAgICAgICIjMDAwMDAwIiwiIzAwRkYwMCIsIiM0MjQyNDIiLCIjMDAwMEZGIikKCkNvZG9uVXNhZ2VGcmVxSHVtYW4gPC0gcmVhZC50YWJsZSgKCSIuLi90Uk5BLUd0Uk5BZGIvQ29kb25Vc2FnZUZyZXFIdW1hbi50YWIiLAoJaGVhZGVyID0gVFJVRSwKCXN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCmBgYAoKIyMjIE1ldGh5bGF0aW9uIGRhdGEKCiMjIyMgV2ViLXNjcmFwZQoKYGBge3IsIGV2YWw9RkFMU0V9Cm1ldGh5bGF0aW9uQXJyYXlEYXRhIDwtIGxhcHBseSgKKGVwaVRPQ2ZldGFsVGlzc3Vlc0wgJT4lIAoJcHVsbChhY2Nlc3Npb24pKSwKCWZ1bmN0aW9uKHgpewoJCXBhc3RlMCgJImh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvZ2VvL3Rvb2xzL2dlb21ldGEuY2dpP2FjYz0iLAoJCQkJeCwKCQkJCSImc2NvcGU9ZnVsbCZtb2RlPW1pbmltbCIKCQkpICU+JQoJCXJlYWRfaHRtbCgpICU+JSAjaHRtbF9zdHJ1Y3R1cmUoKQoJCWh0bWxfbm9kZXMoImludGVybmFsLWRhdGEiKSAlPiUgI3ByZSx4ID0gInByZSIKCQlodG1sX3RleHQoKSAlPiUKCQlyZWFkX2RlbGltKGRlbGltID0gIlx0IiwgY29sX25hbWVzID0gRkFMU0UpICU+JSAjYygicHJvYmVJRCIsImJldGEiLCJkZXRlY3Rpb24tcCIpCgkJbXV0YXRlKGFjY2Vzc2lvbj14KQoJfQopCm1ldGh5bGF0aW9uQXJyYXlEYXRhUyA8LSBsYXBwbHkobWV0aHlsYXRpb25BcnJheURhdGEsIGZ1bmN0aW9uKHgpIHt4ICU+JSBzZWxlY3QoWDEsWDIsYWNjZXNzaW9uKX0pCm1ldGh5bGF0aW9uQXJyYXlEYXRhREYgPC0gZG8uY2FsbChyYmluZCwgbWV0aHlsYXRpb25BcnJheURhdGFTKQptZXRoeWxhdGlvbkFycmF5RGF0YURGIDwtIG1ldGh5bGF0aW9uQXJyYXlEYXRhREYgJT4lIHJlbmFtZShwcm9iZUlEID0gWDEsIGJldGEgPSBYMikKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0Kc2F2ZVJEUygKCW1ldGh5bGF0aW9uQXJyYXlEYXRhREYsCglmaWxlID0gImRhdGEvZXBpVE9DRmV0YWxfbWV0aHlsYXRpb25BcnJheURhdGFERi5SZHMiCikKYGBgCgojIyMjIExvYWQgTG9jYWwgZGF0YSBjb3B5CgpgYGB7ciwgZXZhbD1GQUxTRX0KbWV0aHlsYXRpb25BcnJheURhdGFERiA8LSByZWFkUkRTKAoJZmlsZSA9ICJkYXRhL2VwaVRPQ0ZldGFsX21ldGh5bGF0aW9uQXJyYXlEYXRhREYuUmRzIgopCmBgYAoKIyBEYXRhIE92ZXJ2aWV3CgojIyBOIHByb2JlcyBwZXIgc2FtcGxlCgpgYGB7ciwgZXZhbD1GQUxTRX0KbWV0aHlsYXRpb25BcnJheURhdGFERiAlPiUKCWdyb3VwX2J5KGFjY2Vzc2lvbikgJT4lCglzdW1tYXJpc2UobiA9IG4oKSkKYGBgCgojIyBCZXRhIGRlbnNpdHkgcGxvdHMKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNiwgZXZhbCA9IEZBTFNFfQpnZ3Bsb3RseSgKCW1ldGh5bGF0aW9uQXJyYXlEYXRhREYgJT4lCgkJZ2dwbG90KGFlcyhiZXRhLCBjb2xvdXIgPSBhY2Nlc3Npb24pKSArIAoJCQlnZW9tX2RlbnNpdHkoKSArIAoJCQlndWlkZXMoY29sb3VyPUZBTFNFKQopCmBgYAoKIyBEYXRhIFByb2Nlc3NpbmcKCiMjIE1lYW4gYmV0YXMgZnJvbSB0ZWNobmljYWwgcmVwbGljYXRlcwoKTkIga2VlcHMgYW4gYXJpYnRhcnkgYWNjZXNzaW9uIG51bWJlciBmcm9tIGVhY2ggc2FtcGxlIGZvciBjcm9zcyByZWZlcmVuY2luZyB3aXRoIHRpc3N1ZSB0eXBlIGRhdGEKCmBgYHtyLCBldmFsPUZBTFNFfQptZWFuQmxvb2RCZXRhcyA8LSBlcGlUT0NmZXRhbFRpc3N1ZXNMICU+JSAKCWZpbHRlcighY29yZEJsb29kX2dyb3VwcyA9PSAiTkEiKSAlPiUgCglleHRyYWN0KAoJCWNvbCA9IGNvcmRCbG9vZF9ncm91cHMsCgkJaW50byA9IGMoInNhbXBsZSIsICJyZXBsaWNhdGUiKSwKCQlyZWdleCA9ICIoQ3RybFxcZCspXyhcXHcpIiwKCQlyZW1vdmUgPSBGQUxTRQoJKSAlPiUKCWdyb3VwX2J5KHNhbXBsZSkgJT4lCglkbyhtZWFuQmV0YXMgPSB7CgkJZGF0YSA8LSAuCgkJbWV0aHlsYXRpb25BcnJheURhdGFERiAlPiUgCgkJZmlsdGVyKAoJCQlhY2Nlc3Npb24gJWluJSAoZGF0YSAlPiUgcHVsbChhY2Nlc3Npb24pICkKCQkpICU+JSAKCQlncm91cF9ieShwcm9iZUlEKSAlPiUgCgkJc3VtbWFyaXNlKGJldGEgPSBtZWFuKGJldGEpLCBhY2Nlc3Npb24gPSBkYXRhJGFjY2Vzc2lvblsxXSkKCX0pCmBgYAoKYGBge3IsZXZhbD1GQUxTRX0Kc2F2ZVJEUygKCW1lYW5CbG9vZEJldGFzLAoJImRhdGEvZXBpVE9DRmV0YWxfbWVhbkJsb29kQmV0YXMuUmRzIgopCmBgYAoKYGBge3IsZXZhbD1GQUxTRX0KbWVhbkJsb29kQmV0YXMgPC0gcmVhZFJEUygKCSJkYXRhL2VwaVRPQ0ZldGFsX21lYW5CbG9vZEJldGFzLlJkcyIKKQpgYGAKClVubmVzdCBhbmQgcmVwbGFjZSBkYXRhIHdpdGggdGVjaG5pY2FsIHJlcGxpY2F0ZXMgd2l0aCB0aGUgbWVhbiB2YWx1ZXMKCmBgYHtyLCBldmFsPUZBTFNFfQptZXRoeWxhdGlvbkFycmF5RGF0YVJlcHRNZWFuc0RGIDwtCmJpbmRfcm93cygKCW1ldGh5bGF0aW9uQXJyYXlEYXRhREYgJT4lCgkJZmlsdGVyKAoJCQlhY2Nlc3Npb24gJWluJSAoCgkJCQllcGlUT0NmZXRhbFRpc3N1ZXNMICU+JSAKCQkJCWZpbHRlcihjb3JkQmxvb2RfZ3JvdXBzID09ICJOQSIpICU+JQoJCQkJcHVsbChhY2Nlc3Npb24pCQoJCQkpCgkJKSwKCW1lYW5CbG9vZEJldGFzICU+JSAKCQl1bm5lc3QoKSAlPiUKCQlzZWxlY3QocHJvYmVJRCwgYmV0YSwgYWNjZXNzaW9uKQopCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CnNhdmVSRFMoCgltZXRoeWxhdGlvbkFycmF5RGF0YVJlcHRNZWFuc0RGLAoJZmlsZSA9ICJkYXRhL2VwaVRPQ0ZldGFsX21ldGh5bGF0aW9uQXJyYXlEYXRhUmVwdE1lYW5zREYuUmRzIgopCmBgYAoKIyMjIyBMb2FkIExvY2FsIGRhdGEgY29weQoKYGBge3J9Cm1ldGh5bGF0aW9uQXJyYXlEYXRhUmVwdE1lYW5zREYgPC0gcmVhZFJEUygKCWZpbGUgPSAiZGF0YS9lcGlUT0NGZXRhbF9tZXRoeWxhdGlvbkFycmF5RGF0YVJlcHRNZWFuc0RGLlJkcyIKKSAKYGBgCgojIyBHZXQgdGlzc3VlIGNhdGVnb3JpZXMKCmBgYHtyfQptZXRoeWxhdGlvbkFycmF5RGF0YVJlcHRNZWFuc0RGIDwtIGxlZnRfam9pbigKCW1ldGh5bGF0aW9uQXJyYXlEYXRhUmVwdE1lYW5zREYsCgllcGlUT0NmZXRhbFRpc3N1ZXNMICU+JSBzZWxlY3QodGlzc3VlLCBhY2Nlc3Npb24pLAoJYnkgPSBjKCJhY2Nlc3Npb24iLCAidGlzc3VlIikKKQpgYGAKCiMgR2V0IG1ldGggZGF0YSBmcm9tIHRSTkEgcHJvYmVzCgpgYGB7cn0KdFJOQXByb2Jlc01ldGhEYXRhIDwtIApsZWZ0X2pvaW4oCgl0Uk5BcHJvYmVzLAoJbWV0aHlsYXRpb25BcnJheURhdGFSZXB0TWVhbnNERiwKCWJ5ID0gInByb2JlSUQiCikgJT4lIAoJZXh0cmFjdCh0Uk5BbmFtZSwKCQkJYygibm10IiwiYWEiLCJjb2RvbiIpLAoJCQkiKFxcdyopLT90Uk5BLShpP1xcd3szfSkoPzpcXHcrKT8tKFxcdyspLSIsCgkJCXJlbW92ZSA9IEZBTFNFCgkpICU+JSAKCW11dGF0ZSh0Uk5BZ2UgPSB0Uk5BbmFtZSAlaW4lICh0Uk5BZ2UgJT4lIHB1bGwodFJOQW5hbWUpKSkKYGBgCgpgYGB7cn0KdFJOQW1lYW5NZXRoQnlUaXNzdWUgPC0KdFJOQXByb2Jlc01ldGhEYXRhICU+JQoJZHBseXI6OnNlbGVjdChwcm9iZUlELCB0Q2hyLCBwU3RhcnQsIHRTdGFydCwgdFJOQW5hbWUsIG5tdCwgYWEsIHN0cmFuZCwgY29kb24sIGJldGEsIGFjY2Vzc2lvbiwgdGlzc3VlLCB0Uk5BZ2UpICU+JQoJZHBseXI6Omdyb3VwX2J5KHRDaHIsIHRTdGFydCwgdFJOQW5hbWUsIG5tdCwgYWEsIHN0cmFuZCwgY29kb24sIHRpc3N1ZSwgYWNjZXNzaW9uLCB0Uk5BZ2UpICU+JQoJc3VtbWFyaXNlKGJldGEgPSBtZWFuKGJldGEpKQpgYGAKCmBgYHtyfQp0Uk5BbWVhbk1ldGhCeVRpc3N1ZSAlPiUgbnJvdygpCgp0Uk5BbWVhbk1ldGhCeVRpc3N1ZSA8LSAKdFJOQW1lYW5NZXRoQnlUaXNzdWUgJT4lCglmaWx0ZXIoIXRSTkFuYW1lICVpbiUgYmx0Uk5BcykKCnRSTkFtZWFuTWV0aEJ5VGlzc3VlICU+JSBucm93KCkKYGBgCgoKIyMgTnVtYmVyIG9mIHRSTkFzIGNvdmVyZWQ6CgpgYGB7cn0KTnRSTkFnZW5lcyA8LSB0Uk5BbWVhbk1ldGhCeVRpc3N1ZSAlPiUKCXVuZ3JvdXAoKSAlPiUKCXNlbGVjdCh0Uk5BbmFtZSkgJT4lCglkaXN0aW5jdCgpICU+JQoJbnJvdygpCk50Uk5BZ2VuZXMKYGBgCgojIyBOdW1iZXIgb2YgdFJOQWdlIGdlbmVzIGNvdmVyZWQKCmBgYHtyfQpOdFJOQWdlR2VuZXMgPC0gdFJOQW1lYW5NZXRoQnlUaXNzdWUgJT4lCgl1bmdyb3VwKCkgJT4lCglmaWx0ZXIodFJOQWdlID09IFRSVUUpICU+JQoJc2VsZWN0KHRSTkFuYW1lKSAlPiUKCWRpc3RpbmN0KCkgJT4lCglucm93KCkKTnRSTkFnZUdlbmVzCmBgYAoKYGBge3J9Cm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWUgPC0gdFJOQXByb2Jlc01ldGhEYXRhICU+JQoJc2VsZWN0KHByb2JlSUQsdENocixwU3RhcnQsdFN0YXJ0LHRSTkFuYW1lLG5tdCxhYSxzdHJhbmQsY29kb24sYmV0YSxhY2Nlc3Npb24sdGlzc3VlKSAlPiUKCWdyb3VwX2J5KHRDaHIsdFN0YXJ0LHRSTkFuYW1lLG5tdCxhYSxzdHJhbmQsY29kb24sdGlzc3VlKSAlPiUKCXN1bW1hcmlzZShiZXRhID0gbWVhbihiZXRhKSkgJT4lCgl1bmdyb3VwKCkKCiMgdFJOQXMgd2l0aCBtZWFuIGJldGEgPCAwLjIgaW4gMSBvciBtb3JlIHRpc3N1ZXMKbWVhbk1ldGhCeXRSTkFCeVRpc3N1ZSAlPiUKCWZpbHRlcihiZXRhIDwgMC4yKSAlPiUgCglzZWxlY3QodFJOQW5hbWUpICU+JSAKCWRpc3RpbmN0KCkgJT4lCglucm93KCkKCiMgdFJOQXMgd2l0aCBtZWFuIGJldGEgPj0gMC4yIGluIDEgb3IgbW9yZSB0aXNzdWVzCm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWUgJT4lCglmaWx0ZXIoYmV0YSA+PSAwLjIpICU+JSAKCXNlbGVjdCh0Uk5BbmFtZSkgJT4lIAoJZGlzdGluY3QoKSAlPiUKCW5yb3coKQpgYGAKCiMjIHRSTkEgbWVhbiBtZXR5bGF0aW9uIGJ5IHRpc3N1ZSBwbG90cwoKIyMjIEhlYXRtYXBzCgpgYGB7cn0KbWVhbk1ldGhCeXRSTkFCeVRpc3N1ZU1hdCA8LSAKdFJOQW1lYW5NZXRoQnlUaXNzdWUgJT4lCgl1bmdyb3VwKCkgJT4lCglzZWxlY3QodFJOQW5hbWUsdGlzc3VlLGJldGEpICU+JQoJZ3JvdXBfYnkodFJOQW5hbWUsdGlzc3VlKSAlPiUKCXN1bW1hcmlzZShtZWFuID0gbWVhbihiZXRhKSkgJT4lCglkcm9wX25hKHRpc3N1ZSkgJT4lCglzcHJlYWQodGlzc3VlLG1lYW4pICU+JQoJbmEub21pdCgpICU+JQoJY29sdW1uX3RvX3Jvd25hbWVzKCJ0Uk5BbmFtZSIpICU+JQoJZGF0YS5tYXRyaXgoKQoKbWVhbk1ldGhCeXRSTkFCeVRpc3N1ZU1hdCAlPiUgbnJvdygpCmBgYAoKYGBge3J9CmNvbF9mdW4gPC0gY2lyY2xpemU6OmNvbG9yUmFtcDIoCgljKDAsIDAuNSwgMSksCgljKCIjZmZmZjAwIiwgIiMxOWZmMDAiLCAiIzAwMzNjYyIpCikKYGBgCgpgYGB7cixmaWcud2lkdGg9OSxmaWcuaGVpZ2h0PTEyfQptZWFuTWV0aEJ5dFJOQUJ5VGlzc3VlSGVhdG1hcCA8LQptZWFuTWV0aEJ5dFJOQUJ5VGlzc3VlTWF0ICU+JQoJSGVhdG1hcCgKCQloZWF0bWFwX3dpZHRoID0gdW5pdCg1LjQsImluY2hlcyIpLAoJCWhlYXRtYXBfaGVpZ2h0ID0gdW5pdCgxMS44LCJpbmNoZXMiKSwKCQljb2x1bW5fdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gMTEsIGZvbnRmYWNlID0gImJvbGQiKSwKCQkjIkZldGFsIFRpc3N1ZSB0Uk5BIG1ldGh5bGF0aW9uIiwKCQljb2x1bW5fdGl0bGUgPSAiTWVhbiBNZXRoeWF0aW9uIGJ5IHRSTkFcbmluIEZldGFsIFRpc3N1ZSIsIAoJCW5hbWUgPSAiTWV0aCIsCgkJY29sdW1uX25hbWVzX3JvdCA9IDQ1LAoJCXJvd19kZW5kX3dpZHRoID0gdW5pdCgwLjIsICJucGMiKSwKCQlyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCgkJcm93X3RpdGxlID0gInRSTkEgZ2VuZSIsCgkJY29sID0gY29sX2Z1bgoJKQoKcG5nKAoJZmlsZW5hbWUgPSAiZ3JhcGhpY3MvbWVhbk1ldGhCeXRSTkFCeUZldGFsVGlzc3VlSGVhdG1hcC5wbmciLAoJI3dpZHRoID0gOSwgaGVpZ2h0ID0gMTIsIHVuaXRzID0gImluIiwgcmVzID0gMTkyCgl3aWR0aCA9IDYsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJpbiIsIHJlcyA9IDE5MgopCm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWVIZWF0bWFwCmRldi5vZmYoKQoKbWVhbk1ldGhCeXRSTkFCeVRpc3N1ZUhlYXRtYXAKYGBgCgpgYGB7cixmaWcud2lkdGg9OSxmaWcuaGVpZ2h0PTEyfQptZWFuTWV0aEJ5dFJOQUJ5VGlzc3VlSGVhdG1hcEFBc3BsaXQgPC0KbWVhbk1ldGhCeXRSTkFCeVRpc3N1ZU1hdCAlPiUKICBIZWF0bWFwKAogICAgaGVhdG1hcF93aWR0aCA9IHVuaXQoNS40LCAiaW5jaGVzIiksCiAgICBoZWF0bWFwX2hlaWdodCA9IHVuaXQoMTEuOCwgImluY2hlcyIpLAogICAgY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDE2LCBmb250ZmFjZSA9ICJib2xkIiksCiAgICBjb2x1bW5fdGl0bGUgPSAiTWVhbiBNZXRoeWF0aW9uIGJ5IHRSTkFcbmluIEZldGFsIFRpc3N1ZSIsCiAgICBuYW1lID0gIk1ldGgiLAogICAgY29sdW1uX25hbWVzX3JvdCA9IDQ1LAogICAgcm93X2RlbmRfd2lkdGggPSB1bml0KDAuMiwgIm5wYyIpLAogICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDYpLAogICAgcm93X3NwbGl0ID0gcm93bmFtZXMobWVhbk1ldGhCeXRSTkFCeVRpc3N1ZU1hdCkgJT4lCiAgICAgIGdzdWIocGF0dGVybiA9ICJ0Uk5BLShcXHcrKS1cXHcrLVxcdystXFxkKyIsIHJlcGxhY2VtZW50ID0gIlxcMSIpLAogICAgcm93X3RpdGxlID0gInRSTkEgZ2VuZSIsCiAgICBjb2wgPSBjb2xfZnVuCiAgKQoKcG5nKAogIGZpbGVuYW1lID0gImdyYXBoaWNzL21lYW5NZXRoQnl0Uk5BQnlGZXRhbFRpc3N1ZUhlYXRtYXBBQXNwbGl0LnBuZyIsCiAgI3dpZHRoID0gOSwgaGVpZ2h0ID0gMTIsIHVuaXRzID0gImluIiwgcmVzID0gMTkyCiAgd2lkdGggPSA2LCBoZWlnaHQgPSAxMiwgdW5pdHMgPSAiaW4iLCByZXMgPSAxOTIKICApCm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWVIZWF0bWFwQUFzcGxpdApkZXYub2ZmKCkKCm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWVIZWF0bWFwQUFzcGxpdApgYGAKCmBgYHtyLGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9MTJ9CnBzZXVkb1NwbGl0IDwtIHRSTkEkcHNldWRvCm5hbWVzKHBzZXVkb1NwbGl0KSA8LSB0Uk5BJHRSTkFuYW1lCiMgcHNldWRvU3BsaXRbcm93bmFtZXMobWVhbk1ldGhCeXRSTkFCeVRpc3N1ZU1hdCldCgptZWFuTWV0aEJ5dFJOQUJ5VGlzc3VlSGVhdG1hcFBzZXVkb3NwbGl0IDwtCm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWVNYXQgJT4lCglIZWF0bWFwKAoJCWhlYXRtYXBfd2lkdGggPSB1bml0KDUuNCwgImluY2hlcyIpLAoJCWhlYXRtYXBfaGVpZ2h0ID0gdW5pdCgxMS44LCAiaW5jaGVzIiksCgkJY29sdW1uX3RpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDE2LCBmb250ZmFjZSA9ICJib2xkIiksCgkJY29sdW1uX3RpdGxlID0gIk1lYW4gTWV0aHlhdGlvbiBieSB0Uk5BXG5pbiBGZXRhbCBUaXNzdWUiLAoJCW5hbWUgPSAiTWV0aCIsCgkJY29sdW1uX25hbWVzX3JvdCA9IDQ1LAoJCXJvd19kZW5kX3dpZHRoID0gdW5pdCgwLjIsICJucGMiKSwKCQlyb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNiksCgkJcm93X3NwbGl0ID0gcHNldWRvU3BsaXRbcm93bmFtZXMobWVhbk1ldGhCeXRSTkFCeVRpc3N1ZU1hdCldLAoJCXJvd190aXRsZSA9ICJ0Uk5BIGdlbmUiLAoJCWNvbCA9IGNvbF9mdW4KCSkKCnBuZygKCWZpbGVuYW1lID0gImdyYXBoaWNzL21lYW5NZXRoQnl0Uk5BQnlGZXRhbFRpc3N1ZUhlYXRtYXBQc2V1ZG9zcGxpdC5wbmciLAoJI3dpZHRoID0gOSwgaGVpZ2h0ID0gMTIsIHVuaXRzID0gImluIiwgcmVzID0gMTkyCgl3aWR0aCA9IDYsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJpbiIsIHJlcyA9IDE5MgopCm1lYW5NZXRoQnl0Uk5BQnlUaXNzdWVIZWF0bWFwUHNldWRvc3BsaXQKZGV2Lm9mZigpCgptZWFuTWV0aEJ5dFJOQUJ5VGlzc3VlSGVhdG1hcFBzZXVkb3NwbGl0CmBgYAoKYGBge3J9CmhlYXRtYXBseShtZWFuTWV0aEJ5dFJOQUJ5VGlzc3VlTWF0KQpgYGAKCiMjIyBCb3hwbG90cwoKYGBge3J9CiMgY3VzdG9tIGxhYmVsZXI6IChjaGFyYWN0ZXIgdmVjdG9yIGluIGFuZCBvdXQpCnRSTkFfbGFiZWxsZXIgPC0gZnVuY3Rpb24odmFsdWUpIHtzYXBwbHkodmFsdWUsCglmdW5jdGlvbihuKXsKCXRSTkFtZWFuTWV0aEJ5VGlzc3VlICU+JQoJCXVuZ3JvdXAoKSAlPiUKCQlzZWxlY3QodFJOQW5hbWUsdENocixzdHJhbmQpICU+JQoJCWRpc3RpbmN0KCkgJT4lCgkJZmlsdGVyKHRSTkFuYW1lPT1hcy5jaGFyYWN0ZXIobikpICU+JQoJCXVubGlzdCgpICU+JQoJCShmdW5jdGlvbihkKSBwYXN0ZTAoZFsidFJOQW5hbWUiXSwiICgiLGRbInN0cmFuZCJdLCIpICIsZFsidENociJdKSkgJT4lCgkJcmV0dXJuKCkKCX0KKX0KYGBgCgpgYGB7cixmaWcud2lkdGg9MTIsZmlnLmhlaWdodD02Ljc1fQpwbG90cyA8LSB0Uk5BbWVhbk1ldGhCeVRpc3N1ZSAlPiUKCWdyb3VwX2J5KGFhKSAlPiUKCQlkbyhwbG90ID0gCgkJCWdncGxvdCguLGFlcyh0aXNzdWUsYmV0YSkpICsKCQkJCSNnZW9tX3BvaW50KCkgKwoJCQkJZ2VvbV9ib3hwbG90KGFlcyhmaWxsPXRpc3N1ZSkpICsgCgkJCQlndWlkZXMoZmlsbD1GQUxTRSkgKwoJCQkJeWxpbSgwLDEpICsKCQkJCWZhY2V0X3dyYXAofnRSTkFuYW1lLGxhYmVsbGVyID0gbGFiZWxsZXIodFJOQW5hbWUgPSB0Uk5BX2xhYmVsbGVyKSkgKyAjLHNjYWxlcyA9ICJmcmVlX3kiCgkJCQlnZW9tX2hsaW5lKGFlcyhjb2xvdXI9dFJOQWdlLHlpbnRlcmNlcHQgPSAwLjIpKSArCgkJCQlzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiPSJyZWQiLCJGQUxTRSI9ImJsYWNrIiksZHJvcD1GQUxTRSkgKwoJCQkJbGFicygJdGl0bGUgPSBwYXN0ZTAoInRSTkEgZ2VuZXMgd2hpY2ggYXJlICIsLiRhYSwiIGlzb2FjY2VwdG9ycyIpLAoJCQkJCQlzdWJ0aXRsZSA9ICJtZWFuIG1ldGh5bGF0aW9uIGFjcm9zcyBhbGwgcHJvYmVzIGluIGEgdFJOQSBnZW5lIGZvciBlYWNoIGZldGFsIHRpc3N1ZSIKCQkJCSkgKyAKCQkJCXRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsdmp1c3QgPSAwLjUpKQoJCSkKCnBsb3RzJHBsb3QKI3Bsb3RzJHBsb3RbWzNdXQojcGxvdHMgJT4lIGZpbHRlcihhYT09ImlNZXQiKSAlPiUgcHVsbChwbG90KQpgYGAKCmBgYHtyLGV2YWw9RkFMU0V9Cm5pbCA8LSBwbG90cyAlPiUgZG8ob3V0PWdnc2F2ZShwbG90ID0gLiRwbG90LAoJCQkJCWZpbGVuYW1lID0gcGFzdGUwKCJncmFwaGljcy9lcGlUT0NmZXRhbFRpc3N1ZXN0Uk5BTWV0aHlsYXRpb24vdFJOQW1lYW5NZXRoQnlUaXNzdWVfIiAsIC4kYWEgLCAiLnBuZyIpLAoJCQkJCXdpZHRoID0gMTIsCgkJCQkJaGVpZ2h0ID0gNi43NQoJCQkJKSkKcm0obmlsKQpgYGAKCiMgRGlmZmVyZW50aWFsIG1ldGh5bGF0aW9uIGJ5IHRpc3N1ZSAKCiMjIEtydXNrYWwtV2FsbGlzIHRlc3QgCgpgYGB7cixmaWcud2lkdGg9MTIsZmlnLmhlaWdodD02fQpuZXN0ZWRCeXRSTkEgPC0gdFJOQXByb2Jlc01ldGhEYXRhICU+JSAKCW5lc3QoLXRSTkFuYW1lKQoKS1d0aXNzdWVCZXRhIDwtIG5lc3RlZEJ5dFJOQSAlPiUgCglncm91cF9ieSh0Uk5BbmFtZSkgJT4lCgltdXRhdGUodGVzdD1wdXJycjo6bWFwKGRhdGEsIH5rcnVza2FsLnRlc3QodGlzc3VlIH4gYmV0YSwgZGF0YSA9IC4pKSkjYW92CgpLV3Rpc3N1ZUJldGFHbGFuY2UgPC0gS1d0aXNzdWVCZXRhICU+JSB1bm5lc3QodGVzdCAlPiUgcHVycnI6Om1hcChicm9vbTo6Z2xhbmNlKSkKS1d0aXNzdWVCZXRhR2xhbmNlICU+JQoJZ2dwbG90KGFlcyh0Uk5BbmFtZSxwLnZhbHVlKSkgKyAKCQlnZW9tX2NvbCgpICsgCgkJZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC4wNSxjb2xvdXI9InJlZCIpICsKCQl0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCx2anVzdCA9IDAuNSkpCmBgYAoKTm8gdFJOQXMgZm9yIHdoaWNoIG1ldGh5bGF0aW9uIHdhcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBiZXR3ZWVuIHRpc3N1ZXMgYnkgS3J1c2thbC1XYWxsaXMgcmFuayBzdW0gdGVzdAoKIyBDb2RvbnMKCiMjIE1lYW4gbWV0aCBieSBjb2RvbgoKYGBge3IsZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9Ni43NX0KdFJOQW1lYW5NZXRoQnlUaXNzdWUgJT4lCglnZ3Bsb3QoLixhZXModGlzc3VlLGJldGEpKSArIyxncm91cD1hYQoJCXN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX2NsX2Jvb3QiKSsKCQlndWlkZXMoZmlsbD1GQUxTRSkgKwoJCXlsaW0oMCwxKSArCgkJZmFjZXRfd3JhcCh+Y29kb24pICsgIyxzY2FsZXMgPSAiZnJlZV95IiNsYWJlbGxlciA9IGxhYmVsbGVyKHRSTkFuYW1lID0gdFJOQV9sYWJlbGxlcikKCQlnZW9tX2hsaW5lKGFlcyhjb2xvdXI9dFJOQWdlLHlpbnRlcmNlcHQgPSAwLjIpKSArCgkJc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIj0icmVkIiwiRkFMU0UiPSJibGFjayIpLGRyb3A9RkFMU0UpICsKCQkjIGxhYnMoCXRpdGxlID0gIngiLCNwYXN0ZTAoInRSTkEgZ2VuZXMgd2hpY2ggYXJlICIsLiRhYSwiIGlzb2FjY2VwdG9ycyIpLAoJCSMgCQlzdWJ0aXRsZSA9ICJtZWFuIG1ldGh5bGF0aW9uIGFjcm9zcyBhbGwgcHJvYmVzIGluIGEgdFJOQSBnZW5lIGZvciBlYWNoIGZldGFsIHRpc3N1ZSIKCQkjICkgKyAKCQl0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLHZqdXN0ID0gMC41KSkKCmBgYAoKdFJOQXMgd2l0aCBjZXJ0YWluIGNvZG9ucyBzZWVtIG1vcmUgbWV0aHlsYXRlZCB0aGFuIG90aGVycywgc29tZSBvZiB0aGUgbW9yZSBtZXRoeWxhdGVkIGNvZG9ucyBzZWVtZWQgdG8gY29ycmVzcG9uZCB0byB0aG9zZSB0aGF0IGRpdmVyZWQgZnJvbSBleHBlY3RhdGlvbiBiYXNlZCBvbiBmcmVxdWVuY3kgb2Ygb2NjdXJhbmNlIGluIHRoZSBleG9tIHNlZSBiZWxvdy4gZS5nLiBHVFQsIENUVC4gVGhlcmVmb3JlIEkgdG9vayBhIGxvb2sgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG1lYW4gbWV0aHlsYXRpb24gbGV2ZWxzIG9uIHRSTkFzIHdpdGggYSBnaXZlbiBjb2RvbiBhbmQgcmVzaWR1YWxzIGZvciB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbnVtYmVyIG9mIHRSTkEgZ2VuZXMgYW5kIGNvZG9uIGZlcXVlbmN5LgoKYGBge3IsIGZpZy53aWR0aCA9IDksIGZpZy5oZWlnaHQgPSA0LjV9CnJldlRyYW5zIDwtIGZ1bmN0aW9uKHgpewogICAgICAgIG50UGFpcnMgPC0gZGF0YS5mcmFtZSgic2Vuc2UiID0gYygiQSIsIlQiLCJHIiwiQyIsIk4iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImFudGlzZW5zZSI9YygiVCIsIkEiLCJDIiwiRyIsIk4iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQogICAgICAgIHN0cnNwbGl0KHgsIE5VTEwpICU+JQogICAgICAgIGxhcHBseShyZXYpICU+JQogICAgICAgIGxhcHBseShmdW5jdGlvbih4KSBudFBhaXJzJGFudGlzZW5zZVttYXRjaCh4LG50UGFpcnMkc2Vuc2UpXSkgJT4lCiAgICAgICAgc2FwcGx5KHBhc3RlLCBjb2xsYXBzZT0iIikKICAgIH0KCmFhQnljb2RvbiA8LSB0Uk5BICU+JSBzZWxlY3QoYWEsY29kb24pICU+JSB1bmlxdWUoKQphYUJ5Y29kb24kY29kb24gPC0gYWFCeWNvZG9uJGNvZG9uICU+JSByZXZUcmFucygpCgpBQVVzYWdlRnJlcUh1bWFuIDwtIGlubmVyX2pvaW4oCkNvZG9uVXNhZ2VGcmVxSHVtYW4sCmFhQnljb2RvbiwKYnk9ImNvZG9uIikgCgpOdFJOQWJ5YWEgPC0gdFJOQSAlPiUgCiAgICBncm91cF9ieShhYSkgJT4lIAogICAgIyMjCiAgICBzdW1tYXJpc2UoIk50Uk5BIj1uKCkpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNC41fQpOdFJOQWJ5Q29kb24gPC0gCnRSTkEgJT4lIAoJZ3JvdXBfYnkoY29kb24pICU+JSAKCXN1bW1hcmlzZSgiTnRSTkEiPW4oKSkKCgpjb2RvblVzYWdlRnJlcU50Uk5BIDwtIAppbm5lcl9qb2luKAoJQUFVc2FnZUZyZXFIdW1hbiAlPiUgZ3JvdXBfYnkoY29kb24pLAoJTnRSTkFieUNvZG9uICU+JSBzZWxlY3QoY29kb24sTnRSTkEpLAoJYnk9ImNvZG9uIgopCgpjb2RvblVzYWdlRnJlcU50Uk5BcGxvdCA8LSAKZ2dwbG90KGNvZG9uVXNhZ2VGcmVxTnRSTkEsYWVzKGNvdW50UGVyVGhvdXNhbmQsTnRSTkEpKSArCglnZW9tX2xhYmVsKGFlcyhsYWJlbD1jb2RvbixmaWxsPWFhKSxzaXplPTQsY29sb3VyPSJ3aGl0ZSIsYWxwaGE9MC44KSArCglzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlKSArCglnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLHNlPUZBTFNFKSArCglsYWJzKAl4ID0gIkNvZG9uIFVzYWdlIC8gY291bnQgcGVyIHRob3VzYW5kIiwKCQkJeSA9ICJOdW1iZXIgb2YgdFJOQSBnZW5lcyIKCSkgKyAKCWd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iQW1pbm8gQWNpZCIpKSArIAoJZ2VvbV90ZXh0KHg9MzUseT0xNywKCQkJbGFiZWw9cGFzdGUwKAknaXRhbGljKHIpficsCgkJCQkJCQknIj0ificsCgkJCQkJCQlzcHJpbnRmKCIlMC4yZiIsCgkJCQkJCQkJcm91bmQoKGNvcihjb2RvblVzYWdlRnJlcU50Uk5BJGNvdW50UGVyVGhvdXNhbmQsY29kb25Vc2FnZUZyZXFOdFJOQSROdFJOQSkpLAoJCQkJCQkJCWRpZ2l0cyA9IDIpKQoJCQkJCQkJKSwKCQkJcGFyc2UgPSBUUlVFCgkpCgpjb2RvblVzYWdlRnJlcU50Uk5BcGxvdAoKI2dnc2F2ZShjb2RvblVzYWdlRnJlcU50Uk5BcGxvdCxmaWxlbmFtZSA9ICJncmFwaGljcy9jb2RvblVzYWdlRnJlcU50Uk5BcGxvdC5wbmciLHdpZHRoPTgsaGVpZ2h0PTQuNSkKYGBgCgpgYGB7cn0KY29kb25Vc2FnZVZzTnRSTkEgPC0gbG0oY29kb25Vc2FnZUZyZXFOdFJOQSRjb3VudFBlclRob3VzYW5kfmNvZG9uVXNhZ2VGcmVxTnRSTkEkTnRSTkEpCmNvZG9uVXNhZ2VWc050Uk5BICU+JSBzdW1tYXJ5KCkKCm1vZGVsIDwtIGxlZnRfam9pbigKCWF1Z21lbnQoY29kb25Vc2FnZVZzTnRSTkEpICU+JQoJCXJlbmFtZSgKCQkJImNvdW50UGVyVGhvdXNhbmQiID0gImNvZG9uVXNhZ2VGcmVxTnRSTkEuY291bnRQZXJUaG91c2FuZCIsCgkJCSJOdFJOQSIgPSAiY29kb25Vc2FnZUZyZXFOdFJOQS5OdFJOQSIKCQkpLAoJY29kb25Vc2FnZUZyZXFOdFJOQSwKCWJ5PWMoImNvdW50UGVyVGhvdXNhbmQiLCJOdFJOQSIpCikKYGBgCgpgYGB7cn0KbWVhbk1ldGhCeWNvZG9uIDwtIHRSTkFwcm9iZXNNZXRoRGF0YSAlPiUgCglncm91cF9ieShjb2RvbikgJT4lIAoJc3VtbWFyaXNlKGJldGE9bWVhbihiZXRhKSkgJT4lIAoJbXV0YXRlKGNvZG9uPXJldlRyYW5zKGNvZG9uKSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2Ljc1fQptb2RlbE1lYW5NZXRoIDwtIGxlZnRfam9pbihtb2RlbCxtZWFuTWV0aEJ5Y29kb24sYnk9ImNvZG9uIikKbW9kZWxNZWFuTWV0aAoKRmV0YWxNZWFuTWV0aFZzQ29kb25Vc2FnZU50Uk5BR2FwIDwtIAptb2RlbE1lYW5NZXRoICU+JQoJZ2dwbG90KGFlcygucmVzaWQsYmV0YSkpICsgCgkJZ2VvbV9sYWJlbChhZXMobGFiZWw9Y29kb24sZmlsbD1hYSksc2l6ZT00LGNvbG91cj0id2hpdGUiLGFscGhhPTAuOCkgKwoJCXNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKCQlnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwoJCWxhYnMoCXRpdGxlPSJGZXRhbCB0aXNzdWUgdFJOQSBtZXRoeWxhdGlvbiIsCgkJCQlzdWJ0aXRsZSA9ICJSZWxhdGlvbnNoaXAgb2YgbWV0aHlsYXRpb24gbGV2ZWwgdG8gJ2dhcCcgYmV0d2VlbiB0Uk5BIGdlbmUgbnVtYmVyIGFuZCB1c2FnZSBmcmVxdWVuY3kiLAoJCQkJeCA9ICJSZXNpZHVhbHMgZnJvbTogQ29kb24gVXNhZ2UgQ291bnQgfiBOdW1iZXIgb2YgdFJOQSBnZW5lcyIsCgkJCQl5ID0gIk1lYW4gbWV0aHlsYXRpb24gYWNyb3NzIHByb2JlcyBpbiB0Uk5BIGdlbmVzIC9wcm9wb3J0aW9uIG1ldGh5bGF0ZWQiCgkJKSsKCQlndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkFtaW5vIEFjaWQiKSkgKyAKCQlnZW9tX3RleHQoeD0xMCx5PTAuNiwKCQkJCWxhYmVsPXBhc3RlMCgJJ2l0YWxpYyhSXjIpficsCgkJCQkJCQkJJyI9In4nLAoJCQkJCQkJCXNwcmludGYoIiUwLjJmIiwKCQkJCQkJCQkJcm91bmQoZ2xhbmNlKGNvZG9uVXNhZ2VWc050Uk5BKSRyLnNxdWFyZWQsCgkJCQkJCQkJCWRpZ2l0cyA9IDQpKQoJCQkJCQkJCSksCgkJCQlwYXJzZSA9IFRSVUUKCQkpCgojIEZldGFsTWVhbk1ldGhWc0NvZG9uVXNhZ2VOdFJOQUdhcCAlPiUgCiMgCWdnc2F2ZShmaWxlbmFtZSA9ICIuLi9ncmFwaGljcy9GZXRhbE1lYW5NZXRoVnNDb2RvblVzYWdlTnRSTkFHYXAucG5nIiwKIyAJCXdpZHRoID0gMTIsCiMgCQloZWlnaHQgPSA2Ljc1CiMgCSkKCkZldGFsTWVhbk1ldGhWc0NvZG9uVXNhZ2VOdFJOQUdhcApgYGAKCiMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCiMgUmVmZXJlbmNlcwoK